

class BaseModel {
    /**
     * 绝对可靠的深拷贝方法（最终版）
     * @returns {this} 完全独立的深拷贝
     */
    clone() {
        const Constructor = this.constructor;
        const cloned = new Constructor();

        const props = this._getAllProperties();

        for (const prop of props) {
            // 跳过函数和构造器
            if (typeof this[prop] === 'function' || prop === 'constructor') continue;

            // 关键修复点：正确获取描述符
            let descriptor = Object.getOwnPropertyDescriptor(this, prop) ||
                Object.getOwnPropertyDescriptor(Object.getPrototypeOf(this), prop);

            // 精准跳过只读getter（必须同时满足：有getter && 没有setter）
            if (descriptor && descriptor.get && !descriptor.set || prop === 'config') {
                //console.log(`[SKIP] 跳过只读属性 ${prop}`);
                continue;
            }

            // 递归克隆
            cloned[prop] = this._deepCloneProperty(this[prop]);
        }

        return cloned;
    }

    /**
     * 终极属性克隆方法
     * @private
     */
    _deepCloneProperty(value) {
        // 基本类型直接返回
        if (value === null || typeof value !== 'object') {
            return value;
        }

        // 处理数组中的子模型
        if (Array.isArray(value)) {
            return value.map(item => {
                if (item instanceof BaseModel) {
                    return item.clone(); // 递归克隆子模型
                } else {
                    return this._deepCloneProperty(item);
                }
            });
        }

        // 处理Date对象
        if (value instanceof Date) {
            return new Date(value.getTime());
        }

        // 处理BaseModel子类
        if (value instanceof BaseModel) {
            return value.clone();
        }

        // 处理普通对象
        if (value.constructor === Object) {
            const clonedObj = {};
            for (const key in value) {
                if (value.hasOwnProperty(key)) {
                    clonedObj[key] = this._deepCloneProperty(value[key]);
                }
            }
            return clonedObj;
        }

        // 其他对象类型（如Map、Set等）可以在这里扩展
        // 目前直接返回原对象（浅拷贝）
        return value;
    }

    /**
     * 获取所有属性（包括继承链）
     * @private
     */
    _getAllProperties() {
        const props = new Set();
        let obj = this;

        do {
            Object.getOwnPropertyNames(obj).forEach(prop => {
                // 不再跳过以下划线开头的属性
                if (prop !== 'constructor') {
                    props.add(prop);
                }
            });
            obj = Object.getPrototypeOf(obj);
        } while (obj && obj !== Object.prototype);

        return Array.from(props);
    }
}

class SignModel extends BaseModel {
    constructor(freq, name, index, gain, min_gain, max_gain, q, min_q, max_q, select, min_freq, max_freq) {
        super();
        this.freq = freq;
        this.name = name;
        this.index = index;
        this.gain = gain;
        this.min_gain = min_gain;
        this.max_gain = max_gain;
        this.q = q;
        this.min_q = min_q;
        this.max_q = max_q;
        this.select = select;
        this.min_freq = min_freq;
        this.max_freq = max_freq;
    }
}

class ChannelModel extends BaseModel {
    constructor(num, name, mute, phase, db, max_db, min_db, select, hex_line, delay, min_delay, max_delay, high_pass, low_pass, sign_list, target_list, limit_level, min_limit_level, max_limit_level, limit_speed, min_limit_speed, max_limit_speed, limit_release, min_limit_release, max_limit_release) {
        super();
        this.num = num;
        this.name = name;
        this.mute = mute;
        this.phase = phase;
        this.db = db;
        this.max_db = max_db;
        this.min_db = min_db;
        this.select = select;
        this.hex_line = hex_line;
        this.delay = delay;
        this.min_delay = min_delay;
        this.max_delay = max_delay;
        this.high_pass = high_pass;
        this.low_pass = low_pass;
        this.sign_list = sign_list;
        this.target_list = target_list;

        this.limit_level = limit_level;
        this.min_limit_level = min_limit_level;
        this.max_limit_level = max_limit_level;
        this.limit_speed = limit_speed;
        this.min_limit_speed = min_limit_speed;
        this.max_limit_speed = max_limit_speed;
        this.limit_release = limit_release;
        this.min_limit_release = min_limit_release;
        this.max_limit_release = max_limit_release;
        
        this.custom_name = '';
    }
}

class PassModel extends BaseModel {
    constructor(freq, min_freq, max_freq, is_high, type_index, types) {
        super();
        this.freq = freq;
        this.min_freq = min_freq;
        this.max_freq = max_freq;
        this.is_high = is_high;
        this.type_index = type_index;
        this.types = types;
    }
    get type() {
        return this.types[this.type_index];
    }
}

class PassType extends BaseModel {
    constructor(name, type, slope, slopeList) {
        super();
        this.name = name;
        this.slope = slope;
        this.type = type;
        this.slopeList = slopeList;
    }

    get oct_type() {
        switch (this.type) {
            case 0: //bessel
                switch (this.slope) {
                    case 6:
                        return 0;
                    case 12:
                        return 6;
                    case 18:
                        return 7;
                    case 24:
                        return 8;
                    case 36:
                        return 9;
                    case 48:
                        return 10;
                    default:
                        return -1;
                }
            case 1: //btr-w
                switch (this.slope) {
                    case 6:
                        return 0;
                    case 12:
                        return 1;
                    case 18:
                        return 2;
                    case 24:
                        return 3;
                    case 36:
                        return 4;
                    case 48:
                        return 5;
                    default:
                        return -1;
                }

            case 2: //link-r
                switch (this.slope) {
                    case 6:
                        return 0;
                    case 12:
                        return 11;
                    case 24:
                        return 12;
                    case 36:
                        return 13;
                    case 48:
                        return 14;
                    default:
                        return -1;
                }
            default:
                return -1;
        }

    }

    get slope_hex() {
        switch (this.type) {
            case 0: //bessel
                switch (this.slope) {
                    case 6:
                        return 0;
                    case 12:
                        return 1;
                    case 18:
                        return 2;
                    case 24:
                        return 3;
                    case 36:
                        return 4;
                    case 48:
                        return 5;
                    default:
                        return 0;
                }
            case 1: //bt-w
                switch (this.slope) {
                    case 6:
                        return 0;
                    case 12:
                        return 1;
                    case 18:
                        return 2;
                    case 24:
                        return 3;
                    case 36:
                        return 4;
                    case 48:
                        return 5;
                    default:
                        return 0;
                }
            case 2: //link-r
                switch (this.slope) {
                    case 6:
                        return 0;
                    case 12:
                        return 1;
                    case 24:
                        return 2;
                    case 36:
                        return 3;
                    case 48:
                        return 4;
                    default:
                        return 0;
                }
            default:
                return 0;
        }
    }
}


class ChannelManager extends BaseModel {
    constructor(chlist = [], source_list, current_source_list, sum_list, current_sum, db, min_db, max_db, mute, delayType, noise, isbyPass) {
        super();
        this.chlist = chlist;
        this.source_list = source_list;
        this.current_source_list = current_source_list;
        this.sum_list = sum_list;
        this.current_sum = current_sum;
        this.db = db;
        this.min_db = min_db;
        this.max_db = max_db;
        this.mute = mute;
        this.delayType = delayType;
        this.noise = noise;
        this.isbyPass = isbyPass;
        this._config = null;
        this._default_ch = null;
        this._group_list = null;
    }

    get current_chlist() {
        const safeList = Array.isArray(this.chlist) ? this.chlist : [];
        const list = safeList.filter(ch => ch?.select);
        return list.length === 0 ? [this.default_ch] : list;
    }

    get default_ch() {
        return this._default_ch;
    }

    get config() {
        return this._config;
    }

    get group_list() {
        return this._group_list;
    }

    set config(new_config) {
        this._config = new_config;
        this.chlist = [];
        this._default_ch = initCH(new_config, '#FFFFFF', -1);
        this.chlist = new_config.colorList.map((e, i) => initCH(new_config, e, i));
        this._group_list = Array.from({ length: this.chlist.length / 2 }, (_, i) => false);
    }
}

export function initCH(config, hex_line, i) {
    const bessel = new PassType('BESSEL', 0, 12, [12, 24, 36, 48]);
    const butter_w = new PassType('BTR-W', 1, 12, [12, 24, 36, 48]);
    const link_r = new PassType('LINK-R', 2, 12, [12, 24, 36, 48]);
    const high = new PassModel(20, 20, 20000, true, 0, [bessel, butter_w, link_r]);
    const low = new PassModel(20000, 20, 20000, false, 0, [bessel.clone(), butter_w.clone(), link_r.clone()]);

    const eqlist = config.freqList.map((e, i) => new SignModel(e, `${e}`, i, 0, config.min_gain, config.max_gain, 7.2, 0.5, 20, false, 20, 20000));
    const target_list = Array.from({ length: config.inputNum }, (_, i) => 0);
    return new ChannelModel(i + 1, `CH${i + 1}`, false, false, 0, 0, -60, false, hex_line ?? config.colorList[i], 0, 0, config.max_delay, high, low, eqlist, target_list, 0, -24, 24, 5, 5, 23, 1, 1, 10000);
}

export {
    ChannelManager, ChannelModel, PassModel,
    PassType, SignModel
};

